﻿using System;
using System.Collections.Generic;
using System.Linq;
using Assist;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using YArchitech.Revit;
using HYRevitCode.ElementSearchUtility.LinkDocumentSuite;
using TableTools.Utilities;
using TopologySearch;

namespace HyDrawSelectArea
{
	public class CollectSelAreaElement
	{
		public CollectSelAreaElement(UIApplication uiApp)
		{
			this.m_uiApp = uiApp;
			this.m_doc = uiApp.ActiveUIDocument.Document;
			this.m_view3D = this.GetView3D();
		}

		private View3D GetView3D()
		{
			List<Element> list = new FilteredElementCollector(this.m_doc).OfClass(typeof(View3D)).OfCategory(BuiltInCategory.OST_Views).ToElements().ToList<Element>();
			View3D view3D = null;
			if (list.Count > 0)
			{
				foreach (Element element in list)
				{
					view3D = (element as View3D);
                    if (view3D.ViewName == "三维统计")
                    {
                        return view3D;
                    }
				}
			}
			Transaction transaction = new Transaction(this.m_doc, "Create 3D view");
			transaction.Start();
			try
			{
                XYZ direction = new XYZ(-1.0, 1.0, -1.0);
                view3D = RevitVersionFuncs.NewView3D(this.m_doc, direction);
                view3D.ViewName = "三维统计";
                transaction.Commit();
			}
			catch
			{
				transaction.RollBack();
			}
			return view3D;
		}

		public List<Element> CollectAllElementInArea(bool bLink, Autodesk.Revit.DB.View view, List<ElementId> lstSelDetailCurveId)
		{
			if (lstSelDetailCurveId.Count <= 0)
			{
				return null;
			}
			List<Element> result = new List<Element>();
			List<LinkCurve> closeArea = this.GetCloseArea(lstSelDetailCurveId);
			foreach (LinkCurve linkCurve in closeArea)
			{
				List<XYZ> areaPts = this.GetAreaPts(linkCurve);
				FilteredElementCollector collector = new FilteredElementCollector(this.m_doc, view.Id);
				this.GetAllElementInArea(areaPts, collector, lstSelDetailCurveId, ref result);
			}
			if (bLink)
			{
				if (this.m_view3D == null)
				{
					return result;
				}
				ViewPlan viewPlan = view as ViewPlan;
				double elevation = viewPlan.GenLevel.Elevation;
				double nearTopElevation = this.GetNearTopElevation(elevation);
				BoundingBoxUV outline = viewPlan.Outline;
				UV uv = outline.Min * (double)viewPlan.Scale;
				UV uv2 = outline.Max * (double)viewPlan.Scale;
				BoundingBoxIntersectsFilter input = new BoundingBoxIntersectsFilter(new Outline(new XYZ(uv.U, uv.V, elevation), new XYZ(uv2.U, uv2.V, nearTopElevation)));
				foreach (RevitLinkInstance revitLinkInstance in this.GetAllRevitLinkInstancesInDoc())
				{
					FilteredElementCollectorLinkDocument filteredElementCollectorLinkDocument = new FilteredElementCollectorLinkDocument(revitLinkInstance.GetLinkDocument());
					filteredElementCollectorLinkDocument.AddViewLimit(input);
					List<BaseLinkDocumentResultBean> lstBeans = filteredElementCollectorLinkDocument.OfCalss(typeof(FamilyInstance)).ToBeans();
					foreach (LinkCurve linkCurve2 in closeArea)
					{
						List<XYZ> areaPts2 = this.GetAreaPts(linkCurve2);
						this.GetAllElementInArea(revitLinkInstance, areaPts2, lstBeans, lstSelDetailCurveId, ref result);
					}
				}
			}
			return result;
		}

		public List<Element> CollectAllElementInAreaDoorAndWin(bool bLink, Autodesk.Revit.DB.View view, List<ElementId> lstSelDetailCurveId)
		{
			if (lstSelDetailCurveId.Count <= 0)
			{
				return null;
			}
			List<Element> result = new List<Element>();
			List<LinkCurve> closeArea = this.GetCloseArea(lstSelDetailCurveId);
			foreach (LinkCurve linkCurve in closeArea)
			{
				List<XYZ> areaPts = this.GetAreaPts(linkCurve);
				FilteredElementCollector collector = new FilteredElementCollector(this.m_doc, view.Id);
				this.GetAllElementInArea(areaPts, collector, lstSelDetailCurveId, ref result);
			}
			if (bLink)
			{
				if (this.m_view3D == null)
				{
					return result;
				}
				ViewPlan viewPlan = view as ViewPlan;
				double elevation = viewPlan.GenLevel.Elevation;
				double num = this.GetNearTopElevation(elevation);
				num -= 0.1;
				BoundingBoxUV outline = viewPlan.Outline;
				UV uv = outline.Min * (double)viewPlan.Scale;
				UV uv2 = outline.Max * (double)viewPlan.Scale;
				BoundingBoxIntersectsFilter input = new BoundingBoxIntersectsFilter(new Outline(new XYZ(uv.U, uv.V, elevation), new XYZ(uv2.U, uv2.V, num)));
				foreach (RevitLinkInstance revitLinkInstance in this.GetAllRevitLinkInstancesInDoc())
				{
					FilteredElementCollectorLinkDocument filteredElementCollectorLinkDocument = new FilteredElementCollectorLinkDocument(revitLinkInstance.GetLinkDocument());
					filteredElementCollectorLinkDocument.AddViewLimit(input);
					List<BaseLinkDocumentResultBean> lstBeans = filteredElementCollectorLinkDocument.OfCalss(typeof(FamilyInstance)).ToBeans();
					foreach (LinkCurve linkCurve2 in closeArea)
					{
						List<XYZ> areaPts2 = this.GetAreaPts(linkCurve2);
						this.GetAllElementInArea(revitLinkInstance, areaPts2, lstBeans, lstSelDetailCurveId, ref result);
					}
				}
			}
			return result;
		}

		private List<RevitLinkInstance> GetAllRevitLinkInstancesInDoc()
		{
			IEnumerable<ElementId> enumerable = new FilteredElementCollector(this.m_doc).OfClass(typeof(RevitLinkInstance)).ToElementIds();
			List<RevitLinkInstance> list = new List<RevitLinkInstance>();
			foreach (ElementId elementId in enumerable)
			{
				Element element = this.m_doc.GetElement(elementId);
				if (!(element.GetType() != typeof(RevitLinkInstance)))
				{
					RevitLinkInstance revitLinkInstance = element as RevitLinkInstance;
					if (revitLinkInstance != null)
					{
						list.Add(revitLinkInstance);
					}
				}
			}
			return list;
		}

		private double GetNearTopElevation(double dCurElevation)
		{
			IList<Element> list = new FilteredElementCollector(this.m_doc).OfClass(typeof(Level)).ToElements();
			int num = 0;
			while (num < list.Count && num != list.Count - 1)
			{
				double elevation = (list[num] as Level).Elevation;
				double elevation2 = (list[num + 1] as Level).Elevation;
				if (Geometry.LessThan(dCurElevation, elevation2) && Geometry.Greaterthan_Or_Equal(dCurElevation, elevation))
				{
					return elevation2;
				}
				num++;
			}
			return dCurElevation + Common.MMToFeet(3000.0);
		}

		private List<LinkCurve> GetCloseArea(List<ElementId> lstSelDetailCurveId)
		{
			List<LinkCurve> list = new List<LinkCurve>();
			List<Pole2D> list2 = new List<Pole2D>();
			foreach (ElementId elementId in lstSelDetailCurveId)
			{
				DetailCurve detailCurve = this.m_doc.GetElement(elementId) as DetailCurve;
				if (detailCurve != null)
				{
					Pole2D item = Pole2D.TransformWallToStructure2DPole(detailCurve.GeometryCurve, ElementId.InvalidElementId, 0.0, 0.0);
					list2.Add(item);
				}
			}
			foreach (List<Curve> curveList in new StructureLoopSearcher(this.m_doc).GetFullFloorEdgeLoops(list2, StructureLoopSearcher.SearchEdgeLocation.SEL_Outside))
			{
				LinkCurve item2 = new LinkCurve(curveList);
				list.Add(item2);
			}
			return list;
		}

		private List<XYZ> GetAreaPts(LinkCurve linkCurve)
		{
			List<XYZ> list = new List<XYZ>();
			foreach (Curve curve in linkCurve.CurveList)
			{
				if (curve is Line)
				{
					XYZ hyendPoint = curve.GetEndPoint(0);
					XYZ hyendPoint2 = curve.GetEndPoint(1);
					list.Add(hyendPoint);
					list.Add(hyendPoint2);
				}
				else if (curve is Arc)
				{
					IList<XYZ> collection = curve.Tessellate();
					list.AddRange(collection);
				}
			}
			return list;
		}

		private void GetAllElementInArea(List<XYZ> lstAreaPts, FilteredElementCollector collector, List<ElementId> lstCloseLineId, ref List<Element> lstElemInArea)
		{
			foreach (ElementId elementId in collector.ToElementIds())
			{
				if (!lstCloseLineId.Contains(elementId))
				{
					Element element = this.m_doc.GetElement(elementId);
					if (element.Location is LocationPoint)
					{
						XYZ point = (element.Location as LocationPoint).Point;
						if (Geometry.PointInPloygon(lstAreaPts, point) != -1)
						{
							lstElemInArea.Add(element);
						}
					}
					else if (element.Location is LocationCurve)
					{
						LocationCurve locationCurve = element.Location as LocationCurve;
						XYZ endPoint = locationCurve.Curve.GetEndPoint(0);
						XYZ endPoint2 = locationCurve.Curve.GetEndPoint(1);
						if (Geometry.PointInPloygon(lstAreaPts, endPoint) != -1 && Geometry.PointInPloygon(lstAreaPts, endPoint2) != -1)
						{
							lstElemInArea.Add(element);
						}
					}
				}
			}
		}

		private void GetAllElementInArea(RevitLinkInstance linkInstrance, List<XYZ> lstAreaPts, List<BaseLinkDocumentResultBean> lstBeans, List<ElementId> lstCloseLineId, ref List<Element> lstElemInArea)
		{
			Transform transform = linkInstrance.GetTransform();
			linkInstrance.GetLinkDocument();
			foreach (BaseLinkDocumentResultBean baseLinkDocumentResultBean in lstBeans)
			{
				Element useElement = baseLinkDocumentResultBean.UseElement;
				if (!lstCloseLineId.Contains(useElement.Id))
				{
					if (useElement.Location is LocationPoint)
					{
						XYZ xyz = (useElement.Location as LocationPoint).Point;
						xyz = transform.OfPoint(xyz);
						if (Geometry.PointInPloygon(lstAreaPts, xyz) != -1)
						{
							lstElemInArea.Add(useElement);
						}
					}
					else if (useElement.Location is LocationCurve)
					{
						LocationCurve locationCurve = useElement.Location as LocationCurve;
						XYZ xyz2 = locationCurve.Curve.GetEndPoint(0);
						xyz2 = transform.OfPoint(xyz2);
						XYZ xyz3 = locationCurve.Curve.GetEndPoint(1);
						xyz3 = transform.OfPoint(xyz3);
						if (Geometry.PointInPloygon(lstAreaPts, xyz2) != -1 && Geometry.PointInPloygon(lstAreaPts, xyz3) != -1)
						{
							lstElemInArea.Add(useElement);
						}
					}
				}
			}
		}

		public List<List<XYZ>> GetAreaPointArr(List<ElementId> lstDrawDetailCurve)
		{
			List<List<XYZ>> list = new List<List<XYZ>>();
			foreach (LinkCurve linkCurve in this.GetCloseArea(lstDrawDetailCurve))
			{
				List<XYZ> areaPts = this.GetAreaPts(linkCurve);
				if (areaPts.Count > 2)
				{
					list.Add(areaPts);
				}
			}
			return list;
		}

		private UIApplication m_uiApp;

		private Document m_doc;

		private View3D m_view3D;
	}
}
